package com.ruoyi.web.controller.front;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.alibaba.fastjson2.JSONObject;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.model.CannedAccessControlList;
import com.qcloud.cos.model.PutObjectRequest;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginBody;
import com.ruoyi.common.entity.Result;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.mapper.SysDictDataMapper;
import com.ruoyi.system.mapper.TbDriverCarInfoMapper;
import com.ruoyi.system.mapper.TbOrderMapper;

import com.ruoyi.system.service.*;
import com.ruoyi.system.vo.DriverCarInfoVO;
import com.ruoyi.system.websocket.WebSocketServer;
import com.ruoyi.web.controller.util.*;
import com.ruoyi.web.core.config.WechatMpConfig;

import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.ITbFeedbackService;
import com.ruoyi.system.service.ITbOrderService;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.mock.web.MockMultipartHttpServletRequest;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;


/**
 * 司机端
 */
@Api(tags = "司机端APP接口")
@RestController
@RequestMapping("/api/driver")
public class DriverController extends BaseController {

    private static final Logger log = LoggerFactory.getLogger(DriverController.class);

    @Autowired
    private ITbOrderService orderService;
    @Autowired
    private SysLoginService loginService;

    @Autowired
    private ISysUserService userService;
    @Autowired
    private ITbFeedbackService feedbackService;

    @Autowired
    private TbOrderMapper tbOrderMapper;

    @Autowired
    private ITbDriverCarInfoService driverCarInfoService;

    @Autowired
    private ITbTrainNumberService tbTrainNumberService;

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    private ITbAppVersionService appVersionService;

    /**
     * 查询驱动程序信息
     *
     * @return {@link AjaxResult }
     */
    @ApiOperation(value = "查询司机信息")
    @GetMapping("/queryDriverInformation")
    public AjaxResult queryDriverInformation(
            @RequestParam(value = "merchantNo", required = true) String merchantNo) {
        return AjaxResult.successBody(this.driverCarInfoService.selectTbDriverCarInfoByMerchantNo(merchantNo));
    }

    @ApiOperation(value = "查询列车时刻表")
    @GetMapping("/inquireAboutTheTrainSchedule")
    public AjaxResult inquireAboutTheTrainSchedule() {
        return AjaxResult.successBody(this.tbTrainNumberService.inquireAboutTheTrainSchedule());
    }

    @Autowired
    private ITbViolationService tbViolationService;

    @ApiOperation(value = "查询违章信息")
    @GetMapping("/checkTheViolationInformation")
    public AjaxResult checkTheViolationInformation() {
        Long userId = StpUtil.getLoginIdAsLong();
        TbDriverCarInfo carInfo = tbDriverCarInfoMapper.selectTbDriverCarInfoById(Long.valueOf(userId));
        TbViolation violation = new TbViolation();
        violation.setPlateNumber(carInfo.getCarNo());
        // 查询违章信息并按违章日期降序排序
        List<TbViolation> tbViolations = tbViolationService.selectTbViolationList(violation)
                .stream()
                .sorted(Comparator.comparing(TbViolation::getViolationDate).reversed())
                .collect(Collectors.toList());

        // 返回带数据的成功响应
        return AjaxResult.success(tbViolations);
    }

    @ApiOperation(value = "根据ID查询违章信息")
    @GetMapping("/checkTheViolationInformationById")
    public AjaxResult checkTheViolationInformationById(@RequestParam(value = "id") Long id) {
        return AjaxResult.success(this.tbViolationService.selectTbViolationById(id));
    }

    @ApiOperation(value = "根据id查询列车时刻表")
    @GetMapping("/inquireAboutTheTrainScheduleByid")
    public AjaxResult inquireAboutTheTrainScheduleById(@RequestParam(value = "id") Long id) {
        return AjaxResult.successBody(this.tbTrainNumberService.selectTbTrainNumberById(id));
    }

    @Autowired
    private TbDriverCarInfoMapper tbDriverCarInfoMapper;

    //查询今日流水余额
    @ApiOperation(value = "查询首页 （今日流水余额、完成单量数等）")
    @GetMapping("/getIndexData")
    public AjaxResult getBalance(HttpServletRequest request) {
        Long userId = StpUtil.getLoginIdAsLong();
        TbDriverCarInfo carInfo = tbDriverCarInfoMapper.selectTbDriverCarInfoById(Long.valueOf(userId));
        return AjaxResult.successBody(orderService.getIndexData(carInfo.getMerchantId()));
    }

    @ApiOperation("司机一键登录")
    @ApiImplicitParams({@ApiImplicitParam(name = "username", value = "用户名", required = true, dataType = "String"),
            @ApiImplicitParam(name = "code", value = "验证码", required = false, dataType = "String")})
    @PostMapping("/login")
    public AjaxResult login(@RequestBody LoginBody loginBody) {
        //考虑之前没登录进去的人app还是验证码，所以写死
        if (StrUtil.isNotBlank(loginBody.getCode()) && loginBody.getCode().equals("888888")) {
            return AjaxResult.successBody(loginService.logInSmoothly(
                    loginBody.getUsername()));
        }

        if (StringUtils.isNotBlank(loginBody.getPassword())) {
            return AjaxResult.successBody(loginService.driverLogin(
                    loginBody.getUsername(), loginBody.getPassword()));
        }
        return AjaxResult.successBody("");
    }

    @ApiOperation(value = "修改司机信息")
    @PostMapping("/updateDriverInfo")
    public AjaxResult updateDriverInfo(@RequestBody JSONObject object) {
        Long userId = StpUtil.getLoginIdAsLong();
        String file = object.getString("avatar");
        TbDriverCarInfo tbDriverCarInfo = new TbDriverCarInfo();
        tbDriverCarInfo.setId(userId);
        tbDriverCarInfo.setAvatar(file);
        tbDriverCarInfoMapper.updateTbDriverCarInfo(tbDriverCarInfo);
        return AjaxResult.successBody("操作成功！");
    }


    /**
     * 更改密码
     *
     * @param loginBody 登录身体
     * @return {@link AjaxResult }
     */
    @ApiOperation(value = "修改密码")
    @PostMapping("/changePassword")
    @RepeatSubmit
    public AjaxResult changePassword(@RequestBody LoginBody loginBody) {
        if (StrUtil.isNotBlank(loginBody.getPassword())
                &&
                StrUtil.isNotBlank(loginBody.getNewPassword())) {
            Long userId = StpUtil.getLoginIdAsLong();
            this.driverCarInfoService.updatePassword(userId, loginBody.getPassword(),
                    loginBody.getNewPassword());
        }
        return AjaxResult.successBody("请输入原密码和新密码");
    }


    @ApiOperation(value = "退出登录")
    @GetMapping(value = "/logout")
    public AjaxResult logout(HttpServletRequest request) {
        String token = request.getHeader("Authori-zation");
        StpUtil.logoutByTokenValue(token);
        return AjaxResult.success();
    }

    @ApiOperation(value = "更新用户推送cid")
    @PostMapping(value = "/updateUserMessagePush")
    public AjaxResult updateUserMessagePush(TbDriverCarInfo driverCarInfo) {
        Long userId = StpUtil.getLoginIdAsLong();
        driverCarInfo.setId(userId);
        driverCarInfoService.updateUserMessagePush(driverCarInfo);
        return AjaxResult.success();
    }

    @ApiOperation(value = "查询当前用户是否在线运营")
    @GetMapping(value = "/queryWhetherCurrentUserOperatesOnline")
    public AjaxResult queryWhetherCurrentUserOperatesOnline(
    ) {
        Long userId = StpUtil.getLoginIdAsLong();
        return AjaxResult.success(driverCarInfoService.selectCidInfoByUserId(userId));
    }

    @ApiOperation(value = "切换online 状态接口")
    @GetMapping(value = "/switchOnlineStatusInterface")
    public AjaxResult switchOnlineStatusInterface(@RequestParam(value = "online", defaultValue = "1") Integer online) {
        Long userId = StpUtil.getLoginIdAsLong();
        this.tbDriverCarInfoMapper.updateDriverCarInfo(userId, online);
        return AjaxResult.success();
    }

    //查询投诉记录
    @ApiOperation(value = "查询投诉记录")
    @GetMapping("/getComplaintRecord")
    public AjaxResult getComplaintRecord(HttpServletRequest request, @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum,
                                         @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {
        Long userId = StpUtil.getLoginIdAsLong();
        TbDriverCarInfo carInfo = tbDriverCarInfoMapper.selectTbDriverCarInfoById(Long.valueOf(userId));
        TbFeedback tbFeedback = new TbFeedback();
        tbFeedback.setMerchantId(carInfo.getMerchantId());
        PageHelper.startPage(pageNum, pageSize);
        tbFeedback.setMerchantId(carInfo.getMerchantId());
        if (carInfo.getMerchantId() == null) {
            return AjaxResult.success(new PageInfo<>(new ArrayList<>()));
        }
        List<TbFeedback> tbFeedbacks = feedbackService.selectTbFeedbackList(tbFeedback);
        PageInfo<TbFeedback> pageInfo = new PageInfo<>(tbFeedbacks);
        return AjaxResult.success(pageInfo);
    }

    @ApiOperation(value = "查询投诉记录详情")
    @GetMapping("/getFrontDataTableById")
    public AjaxResult getFrontDataTableById(Long id) {
        TbFeedback tbFeedback = feedbackService.selectTbFeedbackById(id);
        return AjaxResult.successBody(tbFeedback);
    }

    //查询车费记录
    @ApiOperation(value = "查询车费记录")
    @GetMapping("/getTravelRecord")
    public AjaxResult getTravelRecord(HttpServletRequest request,
                                      @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum,
                                      @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize,
                                      @RequestParam(value = "startDate", required = false) String startDate,
                                      @RequestParam(value = "endDate", required = false) String endDate) {
        Long userId = StpUtil.getLoginIdAsLong();
        TbDriverCarInfo carInfo = tbDriverCarInfoMapper.selectTbDriverCarInfoById(Long.valueOf(userId));
        PageHelper.startPage(pageNum, pageSize);
        TbOrder tbOrder = new TbOrder();
        if (carInfo.getMerchantId() == null) {
            return AjaxResult.success(new PageInfo<>(new ArrayList<>()));
        }
        tbOrder.setMerchantId(carInfo.getMerchantId());
        tbOrder.setTransStatus("S");
        if (StrUtil.isNotBlank(startDate) && StrUtil.isNotBlank(endDate)) {
            tbOrder.setStartDate(startDate);
            tbOrder.setEndDate(endDate);
        }
        List<TbOrder> tbOrders = orderService.selectTbOrderList(tbOrder);
        PageInfo<TbOrder> pageInfo = new PageInfo<>(tbOrders);
        return AjaxResult.success(pageInfo);
    }

    @Autowired
    private SysDictDataMapper sysDictDataMapper;

    @ApiOperation(value = "根据code查询字典数据")
    @GetMapping("/getDicByCode")
    public AjaxResult getDicByCode(String code) {
        List<Map<String, Object>> sysDictData = sysDictDataMapper.getDicByCode(code);
        return AjaxResult.successBody(sysDictData);
    }

    @ApiOperation(value = "查询累计车费总额")
    @GetMapping("/getAccumulatedExpenses")
    public AjaxResult getAccumulatedExpenses(@RequestParam(value = "startDate", required = false) String startDate,
                                             @RequestParam(value = "endDate", required = false) String endDate) {
        Long userId = StpUtil.getLoginIdAsLong();

        TbDriverCarInfo carInfo = tbDriverCarInfoMapper.selectTbDriverCarInfoById(userId);
        BigDecimal d = tbOrderMapper.selectSumByOrderId(carInfo.getMerchantId(), startDate, endDate);
        return AjaxResult.successBody(d);
    }

    //我的资料
    @ApiOperation(value = "我的资料")
    @GetMapping("/getMyData")
    public AjaxResult getMyData(HttpServletRequest request) {
        Long userId = StpUtil.getLoginIdAsLong();
        TbDriverCarInfo carInfo = tbDriverCarInfoMapper.selectTbDriverCarInfoById(userId);
        return AjaxResult.successBody(carInfo);
    }

    //通过userId查询商户号
    public String getCurrMerchantId() {
        return "95162017372P010";
    }

    @ApiOperation(value = "下载导入模板文件")
    @GetMapping("/downloadImportTemplateFile")
    public void downloadImportTemplateFile(HttpServletResponse response, String fileName) throws Exception {
        // 定义文件路径
        String filePath = System.getProperty("user.dir") + "/template/driverCarInfo.xlsx";

        File file = FileUtils.getFile(filePath);
        String newfilename = URLEncoder.encode("巡游出租车驾驶员信息统计表", "UTF-8");
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-disposition", "attachment;filename="
                + newfilename + ".xlsx");
        byte[] buffer = new byte[1024];
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        try {
            fis = FileUtils.openInputStream(file);
            bis = new BufferedInputStream(fis);
            OutputStream os = response.getOutputStream();
            int i = bis.read(buffer);
            while (i != -1) {
                os.write(buffer, 0, i);
                i = bis.read(buffer);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != bis) {
                bis.close();
            }
            if (null != fis) {
                fis.close();
            }
        }
    }

    /**
     * 异步删除文件
     */
    private void asyncDeleteFiles(List<String> filePaths) {
        threadPoolTaskExecutor.execute(() -> {
            for (String filePath : filePaths) {
                try {
                    File file = new File(filePath);
                    if (file.exists()) {
                        file.delete();
                    }
                } catch (Exception e) {
                    log.error("删除文件失败: " + filePath, e);
                }
            }
        });
    }

    @ApiOperation(value = "生成司机二维码")
    @GetMapping("/generateDriverQRCode")
    public void generateDriverQRCode(@RequestParam(value = "id", required = false) Long id,
                                     @RequestParam(value = "ids", required = false) String ids,
                                     @RequestParam(value = "company", required = false) String company,
                                     @RequestParam(value = "startTime", required = false) String startTime,
                                     @RequestParam(value = "endTime", required = false) String endTime,
                                     HttpServletResponse response) {
        ZipOutputStream zipOutputStream = null;
        List<String> tempFiles = new ArrayList<>();
        try {
            List<DriverCarInfoVO> list;

            // 如果提供了ids参数，则使用where in批量查询
            if (StringUtils.isNotEmpty(ids)) {
                List<Long> idList = Arrays.stream(ids.split(","))
                        .filter(StringUtils::isNotEmpty)
                        .map(String::trim)
                        .map(Long::parseLong)
                        .collect(Collectors.toList());
                list = tbDriverCarInfoMapper.selectGenerateDriverCarInfoByIds(idList, startTime, endTime);
            } else if (id != null) {
                // 如果提供了单个id，则按原有逻辑查询
                list = tbDriverCarInfoMapper.selectGenerateDriverCarInfoByCid(id, startTime, endTime);
            } else {
                // 如果没有提供任何id参数，返回空列表
                list = tbDriverCarInfoMapper.selectGenerateDriverCarInfoByCid(id, startTime, endTime);
            }
            System.err.println(JSONUtil.toJsonStr(list));
            // 如果提供了公司名称，则进行筛选
            if (StringUtils.isNotEmpty(company)) {
                list = list.stream()
                        .filter(driver -> company.equals(driver.getCompany()))
                        .collect(Collectors.toList());
            }

            // 设置响应头
            response.setContentType("application/zip");
            response.setHeader("Content-Disposition", "attachment; filename=qrcodes.zip");
            response.setBufferSize(1024 * 1024); // 设置缓冲区大小为1MB

            zipOutputStream = new ZipOutputStream(response.getOutputStream());

            // 设置每批处理的数量
            int batchSize = 50;
            int totalSize = list.size();
            int processedCount = 0;

            while (processedCount < totalSize) {
                // 计算当前批次的数据范围
                int endIndex = Math.min(processedCount + batchSize, totalSize);
                List<DriverCarInfoVO> batchList = list.subList(processedCount, endIndex);

                for (DriverCarInfoVO driverCarInfoVO : batchList) {
                    try {
                        String merchantNo = driverCarInfoVO.getMerchantId();
                        // 如果merchantId为空，使用ID作为文件名
                        String fileName = StringUtils.isEmpty(merchantNo) ?
                                "driver_" + driverCarInfoVO.getId() : merchantNo;

                        String driverName = driverCarInfoVO.getCarNo() + " " + driverCarInfoVO.getName();

                        // 生成二维码图片
                        String filePath = System.getProperty("user.dir") + File.separator + "file" + File.separator + fileName + ".png";
                        tempFiles.add(filePath);
                        File qrCodeFile = FileUtil.file(filePath);
                        try {
                            String params = "merchantNo=" + merchantNo;
                            String content = "https://quansutong.quansuchong.com/h5?sign=" + AESUtil.decrypt(params);
                            // 提高二维码质量
                            QrConfig config = new QrConfig(500, 500);
                            config.setMargin(1);
                            QrCodeUtil.generate(content, config, qrCodeFile);
                        } catch (Exception e) {
                            log.error("生成二维码失败: " + fileName, e);
                            continue;
                        }

                        try {
                            // 读取生成的二维码图片
                            BufferedImage qrCodeImage = ImageIO.read(qrCodeFile);

                            // 创建新图片，与二维码大小相同
                            BufferedImage finalImage = new BufferedImage(
                                    qrCodeImage.getWidth(),
                                    qrCodeImage.getHeight(),
                                    BufferedImage.TYPE_INT_RGB
                            );
                            Graphics2D g2d = finalImage.createGraphics();

                            // 设置抗锯齿
                            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
                            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

                            // 设置白色背景
                            g2d.setColor(Color.WHITE);
                            g2d.fillRect(0, 0, finalImage.getWidth(), finalImage.getHeight());

                            // 绘制二维码
                            g2d.drawImage(qrCodeImage, 0, 0, null);

                            // 设置文字属性
                            Font font = null;
                            try {
                                font = new Font("Microsoft YaHei", Font.BOLD, 20);
                                if (!font.getFamily().equals("Microsoft YaHei")) {
                                    font = new Font("SimSun", Font.BOLD, 20);
                                }
                                if (!font.getFamily().equals("SimSun")) {
                                    font = new Font("宋体", Font.BOLD, 20);
                                }
                            } catch (Exception e) {
                                font = new Font("SansSerif", Font.BOLD, 20);
                            }

                            g2d.setFont(font);

                            // 计算文字位置（居中）
                            FontMetrics metrics = g2d.getFontMetrics(font);
                            int textWidth = metrics.stringWidth(driverName);
                            int textHeight = metrics.getHeight();

                            // 计算文字背景区域
                            int padding = 10; // 文字背景的内边距
                            int bgWidth = textWidth + padding * 2;
                            int bgHeight = textHeight + padding * 2;
                            int bgX = (finalImage.getWidth() - bgWidth) / 2;
                            int bgY = (finalImage.getHeight() - bgHeight) / 2;

                            // 绘制文字背景
                            g2d.setColor(Color.WHITE);
                            g2d.fillRect(bgX, bgY, bgWidth, bgHeight);

                            // 绘制文字
                            g2d.setColor(Color.BLACK);
                            int textX = (finalImage.getWidth() - textWidth) / 2;
                            int textY = (finalImage.getHeight() + metrics.getAscent() - metrics.getDescent()) / 2;
                            g2d.drawString(driverName, textX, textY);

                            g2d.dispose();

                            // 保存最终图片到ZIP
                            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                                ImageIO.write(finalImage, "png", baos);
                                byte[] imageBytes = baos.toByteArray();

                                synchronized (zipOutputStream) {
                                    ZipEntry zipEntry = new ZipEntry(fileName + ".png");
                                    zipOutputStream.putNextEntry(zipEntry);
                                    zipOutputStream.write(imageBytes);
                                    zipOutputStream.closeEntry();
                                }
                            }
                        } catch (IOException e) {
                            log.error("处理图片失败: " + fileName, e);
                            continue;
                        }
                    } catch (Exception e) {
                        log.error("处理司机信息失败: " + driverCarInfoVO.getMerchantId(), e);
                        continue;
                    }
                }

                // 更新已处理数量
                processedCount = endIndex;

                // 每批处理完后强制刷新输出流
                try {
                    synchronized (zipOutputStream) {
                        zipOutputStream.flush();
                    }
                    response.flushBuffer();
                } catch (IOException e) {
                    log.error("刷新响应缓冲区失败", e);
                    break;
                }

                // 记录处理进度
                log.info("已处理 {}/{} 条数据", processedCount, totalSize);
            }
        } catch (Exception e) {
            log.error("生成二维码压缩包失败", e);
        } finally {
            if (zipOutputStream != null) {
                try {
                    synchronized (zipOutputStream) {
                        zipOutputStream.finish();
                        zipOutputStream.close();
                    }
                } catch (IOException e) {
                    log.error("关闭输出流失败", e);
                }
            }
            // 异步删除临时文件
            asyncDeleteFiles(tempFiles);
        }
    }

    @ApiOperation(value = "生成单个司机二维码图片")
    @GetMapping("/generateASingleDriverQrCodeImage")
    public void generateASingleDriverQrCodeImage(Long id, HttpServletResponse response) {
        List<DriverCarInfoVO> list = tbDriverCarInfoMapper.selectGenerateDriverCarInfoByCid(id, null, null);
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=qrcodes.zip");

        // 读取模板图片
        String templatePath = System.getProperty("user.dir") + File.separator + "file" + File.separator + "template" + File.separator + "driver_template.png";
        BufferedImage templateImage = null;
        try {
            templateImage = ImageIO.read(new File(templatePath));
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }

        try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
            for (DriverCarInfoVO driverCarInfoVO : list) {
                String merchantNo = driverCarInfoVO.getMerchantId();
                String driverName = driverCarInfoVO.getCarNo() + " " + driverCarInfoVO.getName();

                // 生成二维码图片
                String filePath = System.getProperty("user.dir") + File.separator + "file" + File.separator + merchantNo + ".png";
                File qrCodeFile = FileUtil.file(filePath);
                try {
                    String params = "merchantNo=" + merchantNo;
                    String content = "https://quansutong.quansuchong.com/h5?sign=" + AESUtil.decrypt(params);
                    QrCodeUtil.generate(content,
                            250, 250, //附带logo
                            qrCodeFile);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                try {
                    // 读取生成的二维码图片
                    BufferedImage qrCodeImage = ImageIO.read(qrCodeFile);

                    // 创建模板图片的副本
                    BufferedImage finalImage = new BufferedImage(
                            templateImage.getWidth(),
                            templateImage.getHeight(),
                            BufferedImage.TYPE_INT_RGB
                    );
                    Graphics2D g2d = finalImage.createGraphics();

                    // 绘制模板图片
                    g2d.drawImage(templateImage, 0, 0, null);

                    // 计算二维码的位置（居中放置）
                    int qrX = (templateImage.getWidth() - qrCodeImage.getWidth()) / 2;
                    int qrY = (templateImage.getHeight() - qrCodeImage.getHeight()) / 2 - 50; // 上移50像素留出空间给文字

                    // 绘制二维码
                    g2d.drawImage(qrCodeImage, qrX, qrY, null);

                    // 设置文字属性
                    Font font;
                    try {
                        font = new Font("SimSun", Font.BOLD, 24);
                    } catch (Exception e) {
                        font = new Font("SansSerif", Font.BOLD, 24);
                    }
                    g2d.setFont(font);
                    g2d.setColor(Color.BLACK);

                    // 计算文字位置（居中）
                    FontMetrics metrics = g2d.getFontMetrics(font);
                    int textWidth = metrics.stringWidth(driverName);
                    int textX = (templateImage.getWidth() - textWidth) / 2;
                    int textY = qrY + qrCodeImage.getHeight() + 20; // 二维码下方40像素

                    // 绘制文字
                    g2d.drawString(driverName, textX, textY);
                    g2d.dispose();

                    // 保存最终图片到ZIP
                    try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                        ImageIO.write(finalImage, "png", baos);
                        byte[] imageBytes = baos.toByteArray();

                        ZipEntry zipEntry = new ZipEntry(merchantNo + ".png");
                        zipOutputStream.putNextEntry(zipEntry);
                        zipOutputStream.write(imageBytes);
                        zipOutputStream.closeEntry();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @ApiOperation(value = "导入模板文件")
    @PostMapping("/importTemplateFile")
    public AjaxResult importTemplateFile(HttpServletRequest request,
                                         @RequestParam("file") MultipartFile mfile) throws Exception {
        String type = mfile.getOriginalFilename();
        if (!type.endsWith("xlsx")) {
            return AjaxResult.error("请上传xlsx格式文件!");
        }
        List<String[]> list = LiExcelHelperUtils.readExcelToStringArray(mfile, 0);
        List<TbDriverCarInfo> addGasDetailslist = new ArrayList<>();
        List<String> errorList = new ArrayList<>();
        for (int i = 1; i < list.size(); i++) {
            String[] str = list.get(i);
            if (str.length < 11) {
                return AjaxResult.error("请下载导入模板编辑后再上传!");
            }
            String serialNumber = (str[0] + "").replace(" ", "");
            String carNo = (str[1] + "").replace(" ", "");
            String driverName = (str[2] + "").replace(" ", "");
            String idCard = (str[3] + "").replace(" ", "");
            String phone = (str[4] + "").replace(" ", "");
            String certificateNumber = (str[5] + "").replace(" ", "");
            String driverLicenseNumber = (str[6] + "").replace(" ", "");
            String classes = (str[7] + "").replace(" ", "");
            String vehicleType = (str[8] + "").replace(" ", "");
            String bankCardNumber = (str[9] + "").replace(" ", "");
            String belongingCompany = (str[10] + "").replace(" ", "");

            System.err.println("serialNumber:" + serialNumber + " carNo:" + carNo + " driverName:" + driverName + " idCard:" + idCard + " phone:" + phone + " certificateNumber:" + certificateNumber + " driverLicenseNumber:" + driverLicenseNumber + " classes:" + classes + " vehicleType:" + vehicleType + " bankCardNumber:" + bankCardNumber + " belongingCompany:" + belongingCompany);
            if (1 == i) {
                if (!"序号".equals(serialNumber) || !"车牌号".equals(carNo) || !"驾驶员姓名".equals(driverName) || !"身份证号".equals(idCard)
                        || !"手机号".equals(phone) || !"从业资格证号".equals(certificateNumber) || !"驾驶证号".equals(driverLicenseNumber) || !"班次类型（正班/副班）".equals(classes)
                        || !"车辆类型".equals(vehicleType) || !"银行卡号（农商行）".equals(bankCardNumber) || !"所属公司".equals(belongingCompany)) {
                    return AjaxResult.error("请下载导入模板编辑后再上传!");
                }
            } else {

                //所有数据为空，则无数据，跳出当前循环
                if (StrUtil.isBlankIfStr(serialNumber) && StrUtil.isBlankIfStr(carNo) && StrUtil.isBlankIfStr(driverName) && StrUtil.isBlankIfStr(idCard) && StrUtil.isBlankIfStr(phone)
                        && StrUtil.isBlankIfStr(certificateNumber) && StrUtil.isBlankIfStr(driverLicenseNumber) && StrUtil.isBlankIfStr(classes)
                        && StrUtil.isBlankIfStr(vehicleType) && StrUtil.isBlankIfStr(bankCardNumber) && StrUtil.isBlankIfStr(belongingCompany)) {
                    break;
                }

                if (!isValidIdCard(idCard)) {
//                    errorList.add(idCard);
                    System.err.println("身份证号格式不正确: " + idCard);
                }

                TbDriverCarInfo gasDetail = new TbDriverCarInfo();
                gasDetail.setCarNo(carNo);
                gasDetail.setName(driverName);
                gasDetail.setSex(getGenderFromIdCard(idCard));
                gasDetail.setIdNumber(idCard);
                gasDetail.setPhone(phone);
                gasDetail.setProfessionalNumber(certificateNumber);
                gasDetail.setLicenseNumber(driverLicenseNumber);
                gasDetail.setShiftType("正班".equals(classes) ? "1" : "2");
                if ("电召出租车".equals(vehicleType)) {
                    gasDetail.setVehicleType("1");
                } else if ("巡游出租车".equals(vehicleType)) {
                    gasDetail.setVehicleType("2");
                } else {
                    gasDetail.setVehicleType("3");
                }
                gasDetail.setBankNumber(bankCardNumber);
                gasDetail.setCompany(belongingCompany);
                addGasDetailslist.add(gasDetail);
            }
        }
        //如果有错误数据，则返回错误信息
        if (errorList.size() > 0) {
            errorList = new ArrayList<>(new HashSet<>(errorList));
            String result = "以下身份证号格式不正确 ：" + String.join(";", errorList);
            return AjaxResult.error(result);
        }
        for (TbDriverCarInfo driverCarInfo : addGasDetailslist) {
            tbDriverCarInfoMapper.insertTbDriverCarInfo(driverCarInfo);
        }

        return AjaxResult.success("导入成功!");
    }

    public String getGenderFromIdCard(String idCard) {
        if (idCard == null) {
            return "2";
        }
        int length = idCard.length();
        if (length == 18) {
            // 18 位身份证号，第 17 位表示性别
            char genderChar = idCard.charAt(16);
            if (Character.isDigit(genderChar)) {
                int genderDigit = Character.getNumericValue(genderChar);
                return genderDigit % 2 == 0 ? "1" : "0";
            }
        } else if (length == 15) {
            // 15 位身份证号，第 15 位表示性别
            char genderChar = idCard.charAt(14);
            if (Character.isDigit(genderChar)) {
                int genderDigit = Character.getNumericValue(genderChar);
                return genderDigit % 2 == 0 ? "1" : "0";
            }
        }
        return "2";
    }

    public boolean isValidIdCard(String idCard) {
        if (idCard == null || idCard.length() == 0) {
            return false;
        }
        // 18位身份证号正则表达式
        String regex18 = "^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$";
        // 15位身份证号正则表达式
        String regex15 = "^[1-9]\\d{5}\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}$";

        if (idCard.length() == 18) {
            if (!Pattern.matches(regex18, idCard)) {
                System.out.println("18 位身份证号不符合正则表达式规则: " + idCard);
                return false;
            }
            // 校验 18 位身份证的校验位
            char[] idCardChars = idCard.toUpperCase().toCharArray();
            int[] weights = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
            char[] checkCodes = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
            int sum = 0;
            for (int i = 0; i < 17; i++) {
                sum += (idCardChars[i] - '0') * weights[i];
            }
            int index = sum % 11;
            if (idCardChars[17] != checkCodes[index]) {
                System.out.println("18 位身份证号校验位不匹配: " + idCard);
                return false;
            }
            return true;
        } else if (idCard.length() == 15) {
            if (!Pattern.matches(regex15, idCard)) {
                System.out.println("15 位身份证号不符合正则表达式规则: " + idCard);
            }
            return Pattern.matches(regex15, idCard);
        }
        System.out.println("身份证号长度既不是 15 位也不是 18 位: " + idCard);
        return false;
    }

    public static void main(String[] args) {
        String idCard = "622102198401284631";
        int[] weights = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
        char[] checkCodes = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
        char[] idCardChars = idCard.toUpperCase().toCharArray();
        int sum = 0;
        for (int i = 0; i < 17; i++) {
            sum += (idCardChars[i] - '0') * weights[i];
        }
        int index = sum % 11;
        char calculatedCheckCode = checkCodes[index];
        char providedCheckCode = idCardChars[17];

        System.out.println("计算出的校验位: " + calculatedCheckCode);
        System.out.println("提供的校验位: " + providedCheckCode);
        System.out.println("校验位是否匹配: " + (calculatedCheckCode == providedCheckCode));
    }

    @ApiOperation(value = "导入商户信息")
    @PostMapping("/importMerchantInfo")
    public AjaxResult importMerchantInfo(@RequestParam("file") MultipartFile mfile) throws Exception {
        String type = mfile.getOriginalFilename();
        if (!type.endsWith("xlsx")) {
            return AjaxResult.error("请上传xlsx格式文件!");
        }
        List<String[]> list = LiExcelHelperUtils.readExcelToStringArray(mfile, 0);
        List<String> errorList = new ArrayList<>();
        int successCount = 0;

        log.info(JSONObject.toJSONString(list));

        // Validate header row
        if (list == null || list.isEmpty() || list.get(0) == null || list.get(0).length < 4) {
            return AjaxResult.error("请下载导入模板编辑后再上传!");
        }

        String[] header = list.get(0);
        if (!"商户号".equals(header[0]) || !"商户法定名称".equals(header[1]) ||
                !"法人代表".equals(header[2]) || !"商户联系电话".equals(header[3])) {
            return AjaxResult.error("请下载导入模板编辑后再上传!");
        }

        for (int i = 1; i < list.size(); i++) {
            String[] str = list.get(i);
            if (str == null || str.length < 4) {
                continue;
            }

            String merchantNo = (str[0] + "").replace(" ", "");
            String merchantName = (str[1] + "").replace(" ", "");
            String legalPerson = (str[2] + "").replace(" ", "");
            String phone = (str[3] + "").replace(" ", "");

            // Skip empty rows
            if (StrUtil.isBlankIfStr(merchantNo) && StrUtil.isBlankIfStr(merchantName) &&
                    StrUtil.isBlankIfStr(legalPerson) && StrUtil.isBlankIfStr(phone)) {
                break;
            }

            // Find drivers by phone
            TbDriverCarInfo query = new TbDriverCarInfo();
            query.setPhone(phone);
            List<TbDriverCarInfo> driverList = driverCarInfoService.selectTbDriverCarInfoList(query);

            if (driverList == null || driverList.isEmpty()) {
                errorList.add("未找到手机号为 " + phone + " 的司机信息");
                continue;
            }

            // Update merchant info for all matching drivers
            int rowSuccessCount = 0;
            for (TbDriverCarInfo driverInfo : driverList) {
                if (StrUtil.isBlankIfStr(driverInfo.getMerchantId())) {
                    driverInfo.setMerchantId(merchantNo);
                    int result = tbDriverCarInfoMapper.updateTbDriverCarInfo(driverInfo);
                    if (result > 0) {
                        rowSuccessCount++;
                        successCount++;
                    }
                }

            }

//            if (rowSuccessCount == 0) {
//                errorList.add("手机号为 " + phone + " 的司机信息更新失败");
//            }
        }

        String message = "导入完成，成功更新 " + successCount + " 条记录";
        if (!errorList.isEmpty()) {
            message += "，失败 " + errorList.size() + " 条记录：" + String.join("；", errorList);
        }

        return AjaxResult.success(message);
    }

    @ApiOperation(value = "导入用户头像")
    @PostMapping("/importUserAvatar")
    public AjaxResult importUserAvatar(@RequestParam("files") MultipartFile[] files,
                                       @RequestParam("company") String company) throws Exception {
        if (files == null || files.length == 0) {
            return AjaxResult.error("请选择要上传的图片文件");
        }

        // 创建临时目录
        String tempDir = System.getProperty("user.dir") + File.separator + "temp" + File.separator + System.currentTimeMillis();
        File tempDirFile = new File(tempDir);
        if (!tempDirFile.exists()) {
            boolean created = tempDirFile.mkdirs();
            if (!created) {
                return AjaxResult.error("创建临时目录失败");
            }
        }

        try {
            List<String> processedFiles = new ArrayList<>();
            int successCount = 0;
            int skipCount = 0;

            for (MultipartFile file : files) {
                if (file.isEmpty()) {
                    continue;
                }

                String fileName = file.getOriginalFilename();
                if (fileName == null) {
                    continue;
                }

                // 只处理图片文件
                if (!fileName.toLowerCase().matches(".*\\.(jpg|jpeg|png|gif)$")) {
                    continue;
                }

                // 从图片文件名中提取姓名（过滤数字和符号）
                String name = fileName.substring(0, fileName.lastIndexOf('.'));
                // 移除文件名中的数字和特殊字符
                name = name.replaceAll("[0-9\\s\\p{P}]+", "");
                // 如果文件名中包含路径，只取最后一部分
                if (name.contains("/")) {
                    name = name.substring(name.lastIndexOf("/") + 1);
                }
                if (name.contains("\\")) {
                    name = name.substring(name.lastIndexOf("\\") + 1);
                }
                // 移除压缩包名称
                if (name.contains("司机照片")) {
                    name = name.replace("司机照片", "");
                }

                // 根据姓名和公司查询司机信息
                TbDriverCarInfo query = new TbDriverCarInfo();
                query.setName(name);
                query.setCompany(company);
                List<TbDriverCarInfo> driverList = driverCarInfoService.selectTbDriverCarInfoList(query);

                if (driverList == null || driverList.size() != 1) {
                    skipCount++;
                    continue;
                }

                // 保存临时文件
                String tempFilePath = tempDir + File.separator + fileName;
                File tempFile = new File(tempFilePath);
                // 确保父目录存在
                File parentDir = tempFile.getParentFile();
                if (!parentDir.exists()) {
                    boolean created = parentDir.mkdirs();
                    if (!created) {
                        log.error("创建临时文件目录失败: " + parentDir.getAbsolutePath());
                        continue;
                    }
                }

                try {
                    file.transferTo(tempFile);
                } catch (IOException e) {
                    log.error("保存临时文件失败: " + tempFilePath, e);
                    continue;
                }

                // 创建MockMultipartFile
                byte[] fileBytes = FileUtils.readFileToByteArray(tempFile);
                MockMultipartFile mockFile = new MockMultipartFile(
                        "file",
                        fileName,
                        "image/" + fileName.substring(fileName.lastIndexOf('.') + 1),
                        fileBytes
                );

                // 创建MockMultipartHttpServletRequest
                MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest();
                request.addFile(mockFile);  // 添加文件到请求

                // 上传到云存储
                Result uploadResult = uploadToCOS(request);
                if (uploadResult.getCode() == 200) {
                    // 更新司机头像
                    TbDriverCarInfo driverInfo = driverList.get(0);
                    driverInfo.setAvatar(uploadResult.getData().toString());
                    tbDriverCarInfoMapper.updateTbDriverCarInfo(driverInfo);
                    successCount++;
                }

                processedFiles.add(tempFilePath);
            }

            // 清理临时文件
            for (String filePath : processedFiles) {
                FileUtils.deleteQuietly(new File(filePath));
            }
            FileUtils.deleteDirectory(tempDirFile);

            return AjaxResult.success(String.format("导入完成，成功处理 %d 个文件，跳过 %d 个文件", successCount, skipCount));
        } catch (Exception e) {
            log.error("导入用户头像失败", e);
            return AjaxResult.error("导入失败：" + e.getMessage());
        }
    }


    public Result uploadToCOS(HttpServletRequest request) throws IOException {
        // 获取文件
        List<MultipartFile> files = ((MultipartHttpServletRequest) request).getFiles("file");
        if (files.isEmpty()) {
            return Result.error("未找到上传文件");
        }

        // 创建临时目录
        String tempDir = System.getProperty("user.dir") + File.separator + "temp" + File.separator + System.currentTimeMillis();
        File tempDirFile = new File(tempDir);
        if (!tempDirFile.exists()) {
            tempDirFile.mkdirs();
        }

        try {
            List<String> processedFiles = new ArrayList<>();
            String webUrl = "";
            String fileName = "";
            for (MultipartFile file : files) {
                // 检查文件类型
                if (!FileTypeCheckerUtil.isAllowedFileType(file)) {
                    return Result.error("文件类型错误!");
                }

                // 生成文件名
                String originalFilename = file.getOriginalFilename();
                String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
                fileName = "COS_" + System.currentTimeMillis() + suffix;
                String filePath = tempDir + File.separator + fileName;

                // 保存临时文件
                File tempFile = new File(filePath);
                file.transferTo(tempFile);
                processedFiles.add(filePath);

                // 上传到COS
                COSClient cosClient = COSClientUtil.getCosClient();
                try {
                    String bucketName = SystemConstant.bucketName;
                    String key = "file/" + fileName;

                    // 上传文件到存储桶
                    PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, tempFile);
                    putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead);
                    cosClient.putObject(putObjectRequest);

                    webUrl = SystemConstant.OBJECT_STORAGE_URL + fileName;
                } finally {
                    cosClient.shutdown();
                }
            }

            // 清理临时文件
            for (String filePath : processedFiles) {
                FileUtils.deleteQuietly(new File(filePath));
            }
            FileUtils.deleteDirectory(tempDirFile);

            return Result.success(fileName);
        } catch (Exception e) {
            log.error("上传文件到COS失败", e);
            return Result.error("上传失败：" + e.getMessage());
        }
    }


    @GetMapping("/querySysVersion")
    public Result newList() {

        return Result.success(this.appVersionService.queryLastNewVersion());
    }


    @GetMapping("/resetPasswordsAllDrivers")
    public Result resetPasswordsAllDrivers() {

        return Result.success(this.driverCarInfoService.resetPasswordsAllDrivers());
    }


    @GetMapping("/sendTest")
    public Result sendTest(String token) {
        String msg = "{\"amount\":\"0.1\",\"audioFile\":\"/file/JQ02202506101015473018565.wav\",\"orderId\":\"JQ02202506100951251738021\",\"type\":\"payment\"}";
        WebSocketServer.sendMessageByToken(token, msg);
        return Result.success();
    }

}
